home *** CD-ROM | disk | FTP | other *** search
- /*
- ** patch.library
- **
- ** Copyright © 1993-1997 by Stefan Fuchs
- ** Freely distributable.
- */
-
- #ifndef _PATCH_INCLUDES_H
- #include "patch_includes.h"
- #endif
-
-
- APTR FindTaskListObject( struct Patch *, APTR, ULONG);
-
- #define LVOMatchPattern -846
- #define LVOMatchPatternNoCase -972
- #define LVOFindTask -294
- #define LVOFreeMem -210
- #define LVOAllocMem -198
- #define LVOStackSwap -732
-
- /****** patch.library/SetPatchA ***************************************
- *
- * NAME
- * SetPatchA -- Changes certain attributes of a patch. (V3)
- * SetPatch -- varargs stub for SetPatchA(). (V3)
- *
- * SYNOPSIS
- * Error = SetPatchA( patch, taglist )
- * D0 A0 A1
- *
- * ULONG Error SetPatchA( struct Patch *, struct TagItem *);
- *
- * Error = SetPatch( patch, ...)
- *
- * ULONG Error SetPatch( struct Patch *, ...);
- *
- * FUNCTION
- * Changes certain attributes of a patch (see TAGS).
- *
- * INPUTS
- * patch = pointer to a patch structure or NULL for no action
- * taglist = pointer to array of tags
- *
- * TAGS
- * PATT_CreateTaskList (ULONG) - Create a TaskList of the given type:
- * TL_TYPE_INCLUDE:
- * all specified tasks will use the patchroutine,
- * all others will ignore it.
- * So if no Task is specified via PATT_AddTask... tags,
- * the patchroutine will be used for NO tasks!
- * TL_TYPE_EXCLUDE:
- * all specified tasks will ignore the patchroutine,
- * all others will use it.
- * So if no Task is specified via PATT_AddTask... tags,
- * the patchroutine will be used for ALL tasks!
- * PATT_DeleteTaskList (BOOL) - Delete any existing TaskList
- * This will return the patch to its default behaviour, which is
- * to call the patchroutine for any task.
- * It is not required to remove the TaskList, before you remove
- * a patch, (via RemovePatchTags()) because this will
- * automatically be done by patch.library.
- * PATT_AddTaskID (struct Task *) - Add a task address to the patch
- * TaskList.
- * Patch.library takes care that one TaskID appears only once
- * in the TaskList.
- * Unlike many tags, you may specify this tag more than once
- * in one taglist to add multiple tasks to the list.
- * PATT_AddTaskName (STRPTR) - Add a task of the given name to
- * the patch TaskList.
- * The string will be copied into an internal buffer.
- * Patch.library takes care that one TaskName appears only once
- * in the TaskList.
- * Unlike many tags, you may specify this tag more than once
- * in one taglist to add multiple tasks to the list.
- * PATT_RemTaskID (struct Task *) - Remove a task address from the
- * patch TaskList
- * Unlike many tags, you may specify this tag more than once
- * in one taglist to add multiple tasks to the list.
- * PATT_RemTaskName (APTR) - Remove a task of the given name from the
- * patch TaskList.
- * Unlike many tags, you may specify this tag more than once
- * in one taglist to add multiple tasks to the list.
- * PATT_Disabled (V4) (BOOL) - Enable (False) or disable (True) a patch.
- * For disabling a patch a nesting counter is provided.
- * In order to restore normal patch execution, the programmer
- * must provide exactly one call to 'enable'
- * for every 'disable'.
- * If a patch is disabled this does not mean, that no task
- * continues to use the patched code. It only makes sure,
- * that no further tasks enter the patch code.
- * If PATT_Disabled,TRUE is set with InstallPatchTags() the
- * patch will not be called until explicitly enabled
- * by a call to SetPatchTags().
- * PATT_AddRemoveHook (V4) (struct Hook *) - Add a Hook, which is called
- * by patch.library whenever a patch is removed from memory.
- * Neither the Hook structure nor the hookfunction are copied
- * into internal memory. So freeing these structures must be
- * accomplished by the hookfunction itself.
- * It must also preserve all registers.
- * The hookobject (Register A2) for this hook is the patch
- * structure.
- * For more information about hooks see utility/hooks.h,
- * utility.library/CallHook() or the RKMs.
- * Unlike many tags, you may specify this tag more than once
- * in one taglist to add multiple tasks to the list.
- * PATT_RemRemoveHook (V4) (struct Hook *) - Remove a Hook installed
- * with PATT_AddRemoveHook.
- * Unlike many tags, you may specify this tag more than once
- * in one taglist to add multiple tasks to the list.
- * PATT_UserData (V5) (ULONG) - Attach userdata to a patch.
- * Use this tag only, if you are the owner (creator) of the
- * patch.
- * PATT_AddTaskPattern (V5) (STRPTR) - Add a pattern of tasknames
- * to the patch TaskList.
- * The pattern may contain dos wildcards.
- * Patch.library takes care that one pattern appears only once
- * in the TaskList.
- * Unlike many tags, you may specify this tag more than once
- * in one taglist to add multiple tasks to the list.
- * This tag only works with kickstart V37+.
- * DO NOT USE this tag, if you patch one of the following
- * dos-functions: MatchPattern() or MatchPatternNocase()
- * PATT_RemTaskPattern (V5) (STRPTR) - Remove a taskpattern from the
- * patch TaskList.
- * Unlike many tags, you may specify this tag more than once
- * in one taglist to add multiple tasks to the list.
- * PATT_StackSize (V5) (ULONG) - Minimum stacksize (in bytes) your
- * function requires.
- * This value should be a multiple of 4 and more than 256.
- * If a taskpattern (see PATT_AddtaskPattern) is active,
- * at least 1500 Bytes should be specified.
- * DO NOT USE this tag, if you patch one of the following
- * exec-functions:
- * FindTask(), AllocMem(), FreeMem() or StackSwap()
- * You may specify zero to turn stack extension off.
- * PATT_Priority (V5) (BYTE) - Priority of the patch
- * valid range: -127...+126
- * It indicates the sequence of patches, if more than
- * one patch for a function is installed.
- * The original code has a priority of 0.
- * Priority: Meaning:
- * >0: patch will be executed before the original
- * <0: patch will be executed after the original
- * =0: patch will be executed instead of the original (default)
- * Normally only the priorities +5, 0, -5 should be used.
- * Changing the priority of an active patch is a difficult
- * operation. It may fail with PATERR_PatchInUse.
- * You MUST NOT change the priority of a patch in respect
- * to the original function (see above).
- *
- * RESULT
- * Error = errorcode as defined in patch.h.
- * PATERR_Ok
- * Indicates success of the operation.
- * PATERR_OutOfMem
- * Indicates that there was not enough memory to
- * complete the operation.
- * PATERR_PatchInUse
- * Indicates that some other task is using the
- * installed function and the priority of the patch
- * can't be changed right now.
- * Your task may wait and try again later.
- * PATERR_InvalidHandle
- * Indicates that the pointer to the patch passed
- * to the function was not or is no longer valid.
- * This might happen, if you pass a wrong pointer or
- * you got the pointer via FindPatch() and another
- * task has removed the patch before this task called
- * RemovePatchTags().
- * PATERR_NoTaskList
- * No valid TaskList is attached to the patch.
- * The SetPatchA() function with the PATT_CreateTaskList
- * tag specified, must be called to allocate a TaskList.
- * PATERR_TaskListExists
- * PATT_CreateTaskList was specified, but there already
- * exists a TaskList.
- * PATERR_InvalidTaskList
- * PATT_CreateTaskList was specified with a wrong
- * parameter.
- * PATERR_KickTooOld
- * PATT_AddTaskPattern was used on a system with
- * Kickstart V36or lower.
- * (No longer possible with patch.library V6+, as
- * Kickstart V37+ is required.)
- * PATERR_InvalidPattern
- * PATT_AddTaskList was used with a string,
- * which contained an invalid pattern.
- * See dos.library ParsePattern() for more informations.
- * PATERR_Restricted
- * PATT_AddTaskPattern or PATT_StackSize was used for a
- * forbidden function (see TAGS).
- *
- * NOTES
- * Using the TaskList feature provided by this function will
- * (by a huge amount in the case of PATT_AddTaskPattern) increase
- * the stackusage of the patched function.
- * See PATT_StackSize for a solution.
- *
- * BUGS
- *
- * SEE ALSO
- * InstallPatchTags(), patch.h, patchtags.h,
- * dos.library/ParsePatternNoCase(), dos.library/ParsePattern()
- *
- ******************************************************************************
- *
- */
-
- ULONG LIBFUNC SetPatchA( REGA0 struct Patch *patch GNUC_REGA0, REGA1 struct TagItem *taglist GNUC_REGA1)
- {
- ULONG Result = PATERR_Ok;
- struct TagItem *tlist;
- struct TLHeader *tasklistheader;
- struct Node *pointer;
- struct MasterPatch *master;
- ULONG bufsize;
- APTR pattern;
-
- if( patch)
- {
- Result = SAVEObtainSemaphore();
- if (Result == 0L)
- {
- if( patch->PS_Node.ln_Type != PS_TYPE_MASTER)
- {
- Result = TestPatchHandle(patch);
- if (Result == 0L)
- {
-
-
-
- if( tlist = FindTagItem(PATT_CreateTaskList, taglist))
- {
- if((tlist->ti_Data == TL_TYPE_EXCLUDE) || (tlist->ti_Data == TL_TYPE_INCLUDE))
- {
- if(patch->PS_PatchCode->PC_TaskList)
- {
- Result = PATERR_TaskListExists;
- }
- else
- {
- if( tasklistheader = BAllocmem( sizeof( struct TLHeader), MEMF_CLEAR | MEMF_PUBLIC))
- {
- NewList( (struct List *)tasklistheader);
- tasklistheader->TL_List.lh_Type = tlist->ti_Data;
- if (tlist->ti_Data == TL_TYPE_INCLUDE)
- {
- tasklistheader->TL_Result1 = 0L;
- tasklistheader->TL_Result2 = 1L;
- }
- else
- {
- tasklistheader->TL_Result1 = 1L;
- tasklistheader->TL_Result2 = 0L;
- }
- patch->PS_PatchCode->PC_TaskList = tasklistheader;
- }
- else
- {
- Result = PATERR_OutOfMem;
- }
- }
- }
- else Result = PATERR_InvalidTaskList;
- if( Result != PATERR_Ok) goto Ende;
- }
-
-
-
- if( GetTagData(PATT_DeleteTaskList, 0L, taglist))
- {
- if(tasklistheader = patch->PS_PatchCode->PC_TaskList)
- {
- patch->PS_PatchCode->PC_TaskList = 0L;
- for (pointer = (struct Node *) tasklistheader->TL_List.lh_Head;
- pointer->ln_Succ;
- pointer = (struct Node *) tasklistheader->TL_List.lh_Head)
- {
- if( pointer->ln_Type == TLI_TYPE_TASKPATTERN)
- AFreemem( ((struct TLNode *)pointer)->TN_Pattern);
- ADeleteMyListNode(pointer);
- }
- AFreemem(tasklistheader);
- }
- }
-
-
-
- if( tlist = FindTagItem(PATT_Disabled, taglist))
- {
- if( tlist->ti_Data)
- {
- if( (patch->PS_Flags & PSF_InternalCall) == 0)
- patch->PS_PatchCode->PC_Disable++;
- }
- else
- {
- patch->PS_PatchCode->PC_Disable--;
- }
- }
-
-
-
- tlist = taglist;
- while( tlist = FindTagItem(PATT_AddTaskID, tlist))
- {
- if( patch->PS_PatchCode->PC_TaskList)
- {
- if( FindTaskListObject( patch, (APTR)tlist->ti_Data, TLI_TYPE_TASKID) == NULL)
- {
- if( pointer = ACreateMyListNode( (struct List *) patch->PS_PatchCode->PC_TaskList, sizeof( struct Node)))
- {
- pointer->ln_Name = (STRPTR)tlist->ti_Data;
- pointer->ln_Type = TLI_TYPE_TASKID; /* This must be set, if everything else is initialized ok */
- }
- else
- {
- Result = PATERR_OutOfMem;
- break;
- }
- }
- }
- else
- {
- Result = PATERR_NoTaskList;
- break;
- }
- tlist++;
- }
- if( Result != PATERR_Ok) goto Ende;
-
-
-
- tlist = taglist;
- while( tlist = FindTagItem(PATT_AddTaskName, tlist))
- {
- if( patch->PS_PatchCode->PC_TaskList)
- {
- if( FindTaskListObject( patch, (APTR)tlist->ti_Data, TLI_TYPE_TASKNAME) == NULL)
- {
- if( pointer = ACreateMyListNodeNamed( (struct List *)patch->PS_PatchCode->PC_TaskList, sizeof( struct Node), (STRPTR)tlist->ti_Data))
- {
- pointer->ln_Type = TLI_TYPE_TASKNAME; /* This must be set, if everything else is initialized ok */
- }
- else
- {
- Result = PATERR_OutOfMem;
- break;
- }
- }
- }
- else
- {
- Result = PATERR_NoTaskList;
- break;
- }
- tlist++;
- }
- if( Result != PATERR_Ok) goto Ende;
-
-
-
- tlist = taglist;
- while( tlist = FindTagItem(PATT_AddTaskPattern, tlist))
- {
- if( patch->PS_PatchCode->PC_TaskList)
- {
- master = GetMasterPatch( patch);
- if (DOSBase == (struct DosLibrary *)(master->MPS_PatchedLibraryBase))
- {
- if (master->MPS_PatchedLVO == LVOMatchPattern)
- {
- Result = PATERR_Restricted;
- break;
- }
- if (master->MPS_PatchedLVO == LVOMatchPatternNoCase)
- {
- Result = PATERR_Restricted;
- break;
- }
- }
- if( FindTaskListObject( patch, (APTR)tlist->ti_Data, TLI_TYPE_TASKPATTERN) == NULL)
- {
- bufsize = strlen( (STRPTR)tlist->ti_Data) * 2 + 2;
- pattern = BAllocmem( bufsize, MEMF_CLEAR | MEMF_PUBLIC);
- if( pattern)
- {
- if( ParsePatternNoCase( (STRPTR)tlist->ti_Data, pattern, bufsize) != -1)
- {
- if( pointer = ACreateMyListNodeNamed( (struct List *)patch->PS_PatchCode->PC_TaskList, sizeof( struct Node) + 4, (STRPTR)tlist->ti_Data))
- {
- ((struct TLNode *)pointer)->TN_Pattern = pattern;
- pointer->ln_Type = TLI_TYPE_TASKPATTERN; /* This must be set, if everything else is initialized ok */
- }
- else
- {
- AFreemem( pattern);
- Result = PATERR_OutOfMem;
- break;
- }
- }
- else
- {
- AFreemem( pattern);
- Result = PATERR_InvalidPattern;
- break;
- }
- }
- else
- {
- Result = PATERR_OutOfMem;
- break;
- }
- }
- }
- else
- {
- Result = PATERR_NoTaskList;
- break;
- }
- tlist++;
- }
- if( Result != PATERR_Ok) goto Ende;
-
-
-
- tlist = taglist;
- while( tlist = FindTagItem(PATT_RemTaskID, tlist))
- {
- ADeleteMyListNode( FindTaskListObject( patch, (APTR)tlist->ti_Data, TLI_TYPE_TASKID));
- tlist++;
- }
-
-
-
- tlist = taglist;
- while( tlist = FindTagItem(PATT_RemTaskName, tlist))
- {
- pointer = FindTaskListObject( patch, (APTR)tlist->ti_Data, TLI_TYPE_TASKNAME);
- ADeleteMyListNode( pointer);
- tlist++;
- }
-
-
-
- tlist = taglist;
- while( tlist = FindTagItem(PATT_RemTaskPattern, tlist))
- {
- if( pointer = FindTaskListObject( patch, (APTR)tlist->ti_Data, TLI_TYPE_TASKPATTERN))
- {
- AFreemem( ((struct TLNode *)pointer)->TN_Pattern);
- ADeleteMyListNode( pointer);
- }
- tlist++;
- }
-
-
-
- tlist = taglist;
- while( tlist = FindTagItem(PATT_AddRemoveHook, tlist))
- {
- AddTail(&(patch->PS_RemoveHookList), (struct Node *)tlist->ti_Data);
- tlist++;
- }
-
-
-
- tlist = taglist;
- while( tlist = FindTagItem(PATT_RemRemoveHook, tlist))
- {
- Remove((struct Node *)tlist->ti_Data);
- tlist++;
- }
-
-
-
- if( tlist = FindTagItem(PATT_UserData, taglist))
- {
- patch->PS_UserData = tlist->ti_Data;
- }
-
-
-
- if( tlist = FindTagItem(PATT_StackSize, taglist))
- {
- master = GetMasterPatch( patch);
- if ((struct Library *)SysBase == master->MPS_PatchedLibraryBase)
- {
- switch( master->MPS_PatchedLVO)
- {
- case LVOStackSwap:
- case LVOAllocMem:
- case LVOFreeMem:
- case LVOFindTask:
- Result = PATERR_Restricted;
- goto Ende;
- }
- }
- patch->PS_StackSize = tlist->ti_Data;
- patch->PS_PatchCode->PC_StackSize = tlist->ti_Data;
- ReCalcStackSize( master);
- }
-
-
-
- /* This shouldn't be called, when installing a patch! */
- if( (patch->PS_Flags & PSF_InternalCall) == 0)
- {
- if( tlist = FindTagItem(PATT_Priority, taglist))
- {
- if( tlist->ti_Data)
- {
- Disable();
- if (TestUsage( patch))
- {
- Enable();
- Result = PATERR_PatchInUse;
- }
- else
- {
- patch->PS_Node.ln_Pri = tlist->ti_Data;
- master = GetMasterPatch( patch);
- Remove( (struct Node *)patch);
- Enqueue( (struct List *)&(master->MPS_PatchHeader), (struct Node *)patch);
- LinkPatch( master);
- CacheClearU();
- Enable();
- }
- }
- }
- }
- }
- }
- else
- {
-
-
-
- master = (struct MasterPatch *)patch;
- if( tlist = FindTagItem(PATT_Attach, taglist))
- {
- master->MPS_PatchedLibraryBase = (struct Library *)tlist->ti_Data;
- Result = ConnectStartType( master);
- }
-
-
-
- if( GetTagData(PATT_Detach, 0L, taglist))
- {
- master->MPS_Flags &= ~MPSF_Attached;
- master->MPS_PatchedLibraryBase = 0L;
- }
-
-
-
- }
- Ende:
- ReleaseSemaphore(&(PatchBase->PB_Semaphore));
-
- if( patch->PS_Node.ln_Type != PS_TYPE_MASTER)
- if( (Result == PATERR_Ok) && ((patch->PS_Flags & PSF_InternalCall) == 0))
- SendNotify( PATCOD_PatchChanged, patch);
- }
- if( patch->PS_Node.ln_Type != PS_TYPE_MASTER)
- patch->PS_Flags &= ~PSF_InternalCall;
- }
- return(Result);
- }
-
- /*--------------------------------------------------------------------------*/
- APTR FindTaskListObject( struct Patch *patch, APTR Object, ULONG code)
- {
- struct Node *pointer;
-
- if( patch->PS_PatchCode->PC_TaskList)
- {
- for (pointer = (struct Node *) patch->PS_PatchCode->PC_TaskList->TL_List.lh_Head;
- pointer->ln_Succ;
- pointer = (struct Node *)pointer->ln_Succ)
- {
- switch( pointer->ln_Type)
- {
- case TLI_TYPE_TASKID:
- if (code == TLI_TYPE_TASKID && Object == pointer->ln_Name)
- return( pointer);
- case TLI_TYPE_TASKNAME:
- if (code == TLI_TYPE_TASKNAME && strcmp(pointer->ln_Name, Object) == 0L)
- return( pointer);
- case TLI_TYPE_TASKPATTERN:
- if (code == TLI_TYPE_TASKPATTERN && strcmp(pointer->ln_Name, Object) == 0L)
- return( pointer);
- }
- }
- }
- return(NULL);
- }
-